home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Networking / OTStreamLogViewer / IC Libraries / ICDialogs.p < prev    next >
Encoding:
Text File  |  2000-09-28  |  24.8 KB  |  766 lines  |  [TEXT/CWIE]

  1. unit ICDialogs;
  2.  
  3. (*    This file is part of the Internet Configuration system and is placed in the public domain for the benefit of all.
  4.  
  5.     This module implements many many tiny little routines that are of great assistance
  6.     to those who use the Dialog Manager as a user interface.  Most of these routines
  7.     are pretty obvious, so there's not a lot of comments in the interface section.
  8.     However there may be comments in the implementation section that you might
  9.     find interesting.
  10. *)
  11.  
  12. interface
  13.  
  14.     uses
  15.         Quickdraw,
  16.         Dialogs;
  17.     
  18.     const
  19.         ditOK = 1;
  20.         ditCancel =2;
  21.         ditDontSave = 3;
  22.         
  23.     (* ***** Better Getters and Setters ***** *)
  24.         
  25.     procedure GetDItemText (dlg: DialogPtr; item: integer; var text: Str255);
  26.     procedure SetDItemText (dlg: DialogPtr; item: integer; text: Str255);
  27.  
  28.     procedure GetDItemKind (dlg: DialogPtr; item: integer; var kind: integer);
  29.     procedure SetDItemKind (dlg: DialogPtr; item: integer; kind: integer);
  30.     function GetDItemHandle (dlg: DialogPtr; item: integer): Handle;
  31.     procedure SetDItemHandle (dlg: DialogPtr; item: integer; itemH: univ Handle);
  32.     procedure GetDItemRect (dlg: DialogPtr; item: integer; var itemRect: Rect);
  33.     procedure SetDItemRect (dlg: DialogPtr; item: integer; const itemRect: Rect);
  34.  
  35.     (* ***** Dialog Control Getters and Setters ***** *)
  36.  
  37.     function GetDControlHandle (dlg: DialogPtr; item: integer): ControlHandle;
  38.     
  39.     function GetDControlEnable (dlg: DialogPtr; item: integer): Boolean;
  40.     procedure SetDControlEnable (dlg: DialogPtr; item: integer; enable: Boolean);
  41.     function GetDControlTitle (dlg: DialogPtr; item: integer): Str255;
  42.     procedure SetDControlTitle (dlg: DialogPtr; item: integer; title: Str255);
  43.     function GetDControlValue (dlg: DialogPtr; item: integer): integer;
  44.     procedure SetDControlValue (dlg: DialogPtr; item: integer; value: integer);
  45.     function GetDControlMaximum (dlg: DialogPtr; item: integer): integer;
  46.     procedure SetDControlMaximum (dlg: DialogPtr; item: integer; value: integer);
  47.     function GetDControlBoolean (dlg: DialogPtr; item: integer): Boolean;
  48.     procedure SetDControlBoolean (dlg: DialogPtr; item: integer; value: Boolean);
  49.     procedure ToggleDControlBoolean (dlg: DialogPtr; item: integer);
  50.  
  51.     (* ***** Default Button Support ***** *)
  52.  
  53.     var
  54.         gDefaultButtonUPP : UserItemUPP;
  55.         
  56.     procedure DefaultButtonUserItem (dlg: DialogPtr; item: integer);
  57.     procedure SetupDefaultButtonUserItem (dlg: DialogPtr; defaultItem, roundRectUserItem: integer);
  58.     (* See comment in implementation part. *)
  59.     
  60.     (* ***** Cool Filter Functions ***** *)
  61.     
  62.     (* Some of this functionality is subsumed by System 7's standard
  63.         filter functions, but IC can't use them because it has to run
  64.         under System 6.
  65.         
  66.         These routines are exported as both UPP and routines because
  67.         some places in IC (such as filter functions that are layered
  68.         on top of these default filter functions) need to call them directly.
  69.     *)
  70.     
  71.     var
  72.         gOKModalFilterUPP : ModalFilterUPP;
  73.         gOKCancelModalFilter : ModalFilterUPP;
  74.         gOKCancelDiscardModalFilter : ModalFilterUPP;
  75.  
  76.     function OKModalFilter (dlg: DialogPtr; var event: EventRecord; var item: integer): Boolean;
  77.     function OKCancelModalFilter (dlg: DialogPtr; var event: EventRecord; var item: integer): Boolean;
  78.     function OKCancelDiscardModalFilter (dlg: DialogPtr; var event: EventRecord; var item: integer): Boolean;
  79.  
  80.     (* ***** Stuff That Should Be In the Dialog Manager ***** *)
  81.  
  82.     function CountDItems (dlg: DialogPtr): integer;
  83.     function GetSelectedDialogTextItem (dlg: DialogPtr): integer;
  84.     function DialogItemHidden(dlg : DialogPtr; item : integer) : Boolean;
  85.     function GetDPopupMenuHandle (dlg: DialogPtr; item: integer): MenuHandle;
  86.     procedure InvalDItem(dlg : DialogPtr; item : integer);
  87.  
  88.     (* ***** Miscellaneous Stuff ***** *)
  89.     
  90.     procedure DrawStyledString (dlg: DialogPtr; item: integer; styledString: Str255);
  91.     procedure ShiftTab (dlg: DialogPtr);
  92.     procedure FlashDItem (dlg: DialogPtr; item: integer);
  93.     function TrackDItem(window : WindowPtr; item : integer) : Boolean;
  94.  
  95.     (* ***** Initialisation ***** *)
  96.     
  97.     procedure InitICDialogs;
  98.  
  99. implementation
  100.  
  101.     uses
  102.         TextUtils,
  103.         Fonts,
  104.         Sound,
  105.         
  106.         ICDebug,
  107.         ICCommonSubs;
  108.         
  109.     (* ***** Better Getters and Setters ***** *)
  110.  
  111.     procedure GetDItemText (dlg: DialogPtr; item: integer; var text: Str255);
  112.         var
  113.             itemH: Handle;
  114.     begin
  115.         itemH := GetDItemHandle(dlg, item);
  116.         GetDialogItemText(itemH, text);
  117.     end; (* GetDItemText *)
  118.  
  119.     procedure SetDItemText (dlg: DialogPtr; item: integer; text: Str255);
  120.         var
  121.             itemH: Handle;
  122.     begin
  123.         itemH := GetDItemHandle(dlg, item);
  124.         SetDialogItemText(itemH, text);
  125.     end; (* SetDItemText *)
  126.  
  127.     procedure GetDItemKind (dlg: DialogPtr; item: integer; var kind: integer);
  128.         var
  129.             junkRect : Rect;
  130.             junkItemH: Handle;
  131.     begin
  132.         GetDialogItem(dlg, item, kind, junkItemH, junkRect);
  133.     end; (* GetDItemKind *)
  134.  
  135.     procedure SetDItemKind (dlg: DialogPtr; item: integer; kind: integer);
  136.         var
  137.             junkKind: integer;
  138.             itemH: Handle;
  139.             itemRect: Rect;
  140.     begin
  141.         GetDialogItem(dlg, item, junkKind, itemH, itemRect);
  142.         SetDialogItem(dlg, item, kind, itemH, itemRect);
  143.     end; (* SetDItemKind *)
  144.  
  145.     function GetDItemHandle (dlg: DialogPtr; item: integer): Handle;
  146.         var
  147.             itemKind: integer;
  148.             itemH: Handle;
  149.             itemRect: Rect;
  150.     begin
  151.         GetDialogItem(dlg, item, itemKind, itemH, itemRect);
  152.         GetDItemHandle := itemH;
  153.     end; (* GetDItemHandle *)
  154.  
  155.     procedure SetDItemHandle (dlg: DialogPtr; item: integer; itemH: univ Handle);
  156.         var
  157.             itemKind: integer;
  158.             junkItemH: Handle;
  159.             itemRect: Rect;
  160.     begin
  161.         GetDialogItem(dlg, item, itemKind, junkItemH, itemRect);
  162.         SetDialogItem(dlg, item, itemKind, itemH, itemRect);
  163.     end; (* SetDItemHandle *)
  164.  
  165.     procedure GetDItemRect (dlg: DialogPtr; item: integer; var itemRect: Rect);
  166.         var
  167.             itemKind: integer;
  168.             itemH: Handle;
  169.     begin
  170.         GetDialogItem(dlg, item, itemKind, itemH, itemRect);
  171.     end; (* GetDItemRect *)
  172.  
  173.     procedure SetDItemRect (dlg: DialogPtr; item: integer; const itemRect: Rect);
  174.         var
  175.             itemKind: integer;
  176.             itemH: Handle;
  177.             tmpItemRect: Rect;
  178.     begin
  179.         GetDialogItem(dlg, item, itemKind, itemH, tmpItemRect);
  180.         tmpItemRect := itemRect;
  181.         SetDialogItem(dlg, item, itemKind, itemH, tmpItemRect);
  182.     end; (* SetDItemRect *)
  183.  
  184.     (* ***** Dialog Control Getters and Setters ***** *)
  185.  
  186.     function GetDControlHandle (dlg: DialogPtr; item: integer): ControlHandle;
  187.     begin
  188.         GetDControlHandle := ControlHandle(GetDItemHandle(dlg, item));
  189.     end; (* GetDControlHandle *)
  190.  
  191.     function GetDControlEnable (dlg: DialogPtr; item: integer): Boolean;
  192.     begin
  193.         GetDControlEnable := (GetDControlHandle(dlg, item)^^.contrlHilite <> 255);
  194.     end; (* GetDControlEnable *)
  195.  
  196.     procedure SetDControlEnable (dlg: DialogPtr; item: integer; enable: Boolean);
  197.         var
  198.             controlH: ControlHandle;
  199.             newHighlight: integer;
  200.     begin
  201.         controlH := GetDControlHandle(dlg, item);
  202.         newHighlight := (255 * ord(not enable));
  203.         if controlH^^.contrlHilite <> newHighlight then begin
  204.             HiliteControl(controlH, newHighlight);
  205.         end; (* if *)
  206.     end; (* SetDControlEnable *)
  207.  
  208.     function GetDControlTitle (dlg: DialogPtr; item: integer): Str255;
  209.         var
  210.             title: Str255;
  211.     begin
  212.         GetControlTitle(GetDControlHandle(dlg, item), title);
  213.         GetDControlTitle := title;
  214.     end; (* GetDControlTitle *)
  215.  
  216.     procedure SetDControlTitle (dlg: DialogPtr; item: integer; title: Str255);
  217.         var
  218.             controlH: ControlHandle;
  219.             oldTitle: Str255;
  220.     begin
  221.         controlH := GetDControlHandle(dlg, item);
  222.         GetControlTitle(controlH, oldTitle);
  223.         if oldTitle <> title then begin
  224.             SetControlTitle(controlH, title);
  225.         end; (* if *)
  226.     end; (* SetDControlTitle *)
  227.  
  228.     function GetDControlValue (dlg: DialogPtr; item: integer): integer;
  229.     begin
  230.         GetDControlValue := GetControlValue(GetDControlHandle(dlg, item));
  231.     end; (* GetDControlValue *)
  232.  
  233.     procedure SetDControlValue (dlg: DialogPtr; item: integer; value: integer);
  234.     begin
  235.         SetControlValue(GetDControlHandle(dlg, item), value);
  236.     end; (* SetDControlValue *)
  237.  
  238.     function GetDControlMaximum (dlg: DialogPtr; item: integer): integer;
  239.     begin
  240.         GetDControlMaximum := GetControlMaximum(GetDControlHandle(dlg, item));
  241.     end; (* GetDControlMaximum *)
  242.  
  243.     procedure SetDControlMaximum (dlg: DialogPtr; item: integer; value: integer);
  244.     begin
  245.         SetControlMaximum(GetDControlHandle(dlg, item), value);
  246.     end; (* SetDControlMaximum *)
  247.  
  248.     function GetDControlBoolean (dlg: DialogPtr; item: integer): Boolean;
  249.     begin
  250.         GetDControlBoolean := (GetControlValue(GetDControlHandle(dlg, item)) <> 0);
  251.     end; (* GetDControlBoolean*)
  252.  
  253.     procedure SetDControlBoolean (dlg: DialogPtr; item: integer; value: Boolean);
  254.     begin
  255.         SetControlValue(GetDControlHandle(dlg, item), ord(value));
  256.     end; (* SetDControlBoolean *)
  257.  
  258.     procedure ToggleDControlBoolean (dlg: DialogPtr; item: integer);
  259.     begin
  260.         SetDControlBoolean(dlg, item, not GetDControlBoolean(dlg, item));
  261.     end; (* ToggleDControlBoolean *)
  262.  
  263.     (* ***** Default Button Support ***** *)
  264.  
  265.     procedure DefaultButtonUserItem (dlg: DialogPtr; item: integer);
  266.         (* This routine is the user item update proc for the rounded rectangle
  267.             user item that denotes the default button. It tests the enabled
  268.             state of the default button (dialog item number 1) and draws the
  269.             rounded rectangle in either grey or black depending on the state.
  270.  
  271.             Note that the dialog item number of the default button is hard
  272.             coded into this routine.  There will be no exceptions!
  273.             
  274.             This routine is exported because it can be called by the application
  275.             directly when it thinks that the default button highlighting needs to be
  276.             updated.
  277.         *)
  278.         var
  279.             itemRect: Rect;
  280.             greyPat : Pattern;
  281.     begin
  282.         {$unused item}
  283.         SetPort(dlg);
  284.         GetDItemRect(dlg, ditOK, itemRect);
  285.         PenSize(3, 3);
  286.         InsetRect(itemRect, -4, -4);
  287.         if not GetDControlEnable(dlg, ditOK) then begin
  288.  
  289.             // Avoid using "qd.gray" so that we can be compiled
  290.             // into a code resource.  Sometimes programming the Mac
  291.             // just sucks.
  292.             
  293.             StuffHex(@greyPat, 'AA55AA55AA55AA55');
  294.             PenPat(greyPat);
  295.         end; (* if *)
  296.         FrameRoundRect(itemRect, 16, 16);
  297.         PenNormal;
  298.     end; (* DefaultButtonUserItem *)
  299.  
  300.     procedure SetupDefaultButtonUserItem (dlg: DialogPtr; defaultItem, roundRectUserItem: integer);
  301.         (* This routine installs the DefaultButtonUserItem as the user item update
  302.             proc for roundRectUserItem.  It also sets the bounding rect of roundRectUserItem
  303.             to exactly encompass the bounding rect of defaultItem, so that you don't
  304.             have to get it exactly right when editing the dialog.
  305.         *)
  306.         var
  307.             itemRect: Rect;
  308.     begin
  309.         ICAssert(defaultItem = 1);
  310.         GetDItemRect(dlg, defaultItem, itemRect);
  311.         InsetRect(itemRect, -10, -10);
  312.         SetDItemRect(dlg, roundRectUserItem, itemRect);
  313.         SetDItemHandle(dlg, roundRectUserItem, Handle(gDefaultButtonUPP));
  314.     end; (* SetupDefaultButtonUserItem *)
  315.  
  316.     (* ***** Cool Filter Functions ***** *)
  317.  
  318.     function DoButtonKey (dlg: DialogPtr; item: integer;
  319.                                                     var event: EventRecord; var resultItem: integer): Boolean;
  320.         (* This function is used to respond to a keyboard event hitting a dialog
  321.             button.  If the button denoted by dlg and item is enabled, the function
  322.             flashes the button, sets resultItem to item, and returns true.
  323.             Otherwise it beeps and sets event to a null event.
  324.         *)
  325.     begin
  326.         if GetDControlEnable(dlg, item) then begin
  327.             resultItem := item;
  328.             FlashDItem(dlg, item);
  329.             DoButtonKey := true;
  330.         end else begin
  331.             SysBeep(10);
  332.             event.what := nullEvent;
  333.             DoButtonKey := false;
  334.         end;
  335.     end; (* DoButtonKey *)
  336.  
  337.     function OKModalFilter (dlg: DialogPtr; var event: EventRecord; var item: integer): Boolean;
  338.         (* This is pretty much the standard modal dialog filter function.  It handles
  339.             mapping returns and enters to the ditOK button, and also deals with
  340.             shift tab.
  341.         *)
  342.         var
  343.             result : Boolean;
  344.             typedChar: char;
  345.     begin
  346.         result := false;
  347.         if (event.what = keyDown) or (event.what = autoKey) then begin
  348.             typedChar := chr(band(event.message, charCodeMask));
  349.             if (typedChar = kCRChar) or (typedChar = kEnterChar) then begin
  350.                 result := DoButtonKey(dlg, ditOK, event, item);
  351.             end else if (typedChar = kTabChar) and (band(event.modifiers, shiftKey) <> 0) then begin
  352.                 if GetSelectedDialogTextItem(dlg) <> 0 then begin
  353.                     ShiftTab(dlg);
  354.                     result := true;
  355.                 end; (* if *)
  356.             end; (* if *)
  357.         end;
  358.         OKModalFilter := result;
  359.     end; (* OKModalFilter *)
  360.  
  361.     function OKCancelModalFilter (dlg: DialogPtr; var event: EventRecord; var item: integer): Boolean;
  362.         (* This is the standard modal filter for dialogs with an OK and a Cancel button.
  363.             It handles all that OKModalFilter does, and then deals with mapping Escape
  364.             and command-dot to ditCancel.
  365.         *)
  366.         var
  367.             result : Boolean;
  368.             typedChar: char;
  369.     begin
  370.         result := OKModalFilter(dlg, event, item);
  371.         if not result and ((event.what = keyDown) or (event.what = autoKey)) then begin
  372.             typedChar := chr(band(event.message, charCodeMask));
  373.             if ((typedChar = '.') and (band(event.modifiers, cmdKey) <> 0)) 
  374.                     or (typedChar = kEscChar) then begin
  375.                 result := DoButtonKey(dlg, ditCancel, event, item);
  376.             end; (* if *)
  377.         end; (* if *)
  378.         OKCancelModalFilter := result;
  379.     end; (* OKCancelModalFilter *)
  380.  
  381.     function OKCancelDiscardModalFilter (dlg: DialogPtr; var event: EventRecord; var item: integer): Boolean;
  382.         (* This is the standard modal filter for dialogs with an OK, Cancel and Dont Save button.
  383.             It handles all that OKCancelModalFilter does, and then deals with mapping 
  384.             command-D to ditDontSave.
  385.         *)
  386.         var
  387.             result : Boolean;
  388.             typedChar: integer;
  389.     begin
  390.         result := OKCancelModalFilter(dlg, event, item);
  391.         if not result and ((event.what = keyDown) or (event.what = autoKey)) then begin
  392.             typedChar := band(event.message, charCodeMask);
  393.             if (typedChar = ord('d')) and (band(event.modifiers, cmdKey) <> 0) then begin
  394.                 result := DoButtonKey(dlg, ditDontSave, event, item);
  395.             end; (* if *)
  396.         end; (* if *)
  397.         OKCancelDiscardModalFilter := result;
  398.     end; (* OKCancelDiscardModalFilter *)
  399.  
  400.     (* ***** Stuff That Should Be In the Dialog Manager ***** *)
  401.  
  402.     function CountDItems (dlg: DialogPtr): integer;
  403.         (* Identical to CountDITL but works under System 6 without Comms Toolbox installed. *)
  404.     begin
  405.         CountDItems := IntegerPtr(DialogPeek(dlg)^.items^)^ + 1;
  406.     end; (* CountDItems*)
  407.  
  408.     function GetSelectedDialogTextItem (dlg: DialogPtr): integer;
  409.         (* Returns the item number of the edit text that contains the insertion point. *)
  410.     begin
  411.         GetSelectedDialogTextItem := DialogPeek(dlg)^.editField + 1;
  412.     end; (* GetSelectedDialogTextItem *)
  413.  
  414.     function DialogItemHidden(dlg : DialogPtr; item : integer) : Boolean;
  415.         (* Returns true if the item has been hidden with HideDialogItem. *)
  416.         var
  417.             itemRect : Rect;
  418.     begin
  419.         GetDItemRect(dlg, item, itemRect);
  420.         DialogItemHidden := (itemRect.top < 16384) and (itemRect.left < 16384);
  421.     end; (* DialogItemHidden *)
  422.  
  423.     function GetDPopupMenuHandle (dlg: DialogPtr; item: integer): MenuHandle;
  424.         (* Returns the MenuHandle for the popup menu dialog item. This is documented
  425.             as being available from the first 4 bytes of the handle pointed to be
  426.             the item's contrlData field.
  427.         *)
  428.         type
  429.             MenuHandlePtr = ^MenuHandle;
  430.             MenuHandleHandle = ^MenuHandlePtr;
  431.     begin
  432.         GetDPopupMenuHandle := MenuHandleHandle(GetDControlHandle(dlg, item)^^.contrlData)^^;
  433.     end; (* GetDPopupMenuHandle*)
  434.  
  435.     procedure InvalDItem(dlg : DialogPtr; item : integer);
  436.         (* Invalidate a dialog item, ie cause it to be redrawn via an update event. *)
  437.         var
  438.             oldPort : GrafPtr;
  439.             itemRect : Rect;
  440.     begin
  441.         GetPort(oldPort);
  442.         SetPort(dlg);
  443.         GetDItemRect(dlg, item, itemRect);
  444.         InvalRect(itemRect);
  445.         SetPort(oldPort);
  446.     end; (* InvalDItem *)
  447.     
  448.     (* ***** Miscellaneous Stuff ***** *)
  449.  
  450.     function Split (delimiter : Str255; str: Str255; var head, tail: Str255): Boolean;
  451.         (* This routine splits str at the first occurence of delimiter and sets
  452.             head to be the text in front of the delimiter and tail to be the text
  453.             behind it.  It returns true if it could find a delimiter (and hence
  454.             perform the split), otherwise it returns false.
  455.         *)
  456.         var
  457.             delimiterPosition: integer;
  458.     begin
  459.         delimiterPosition := pos(delimiter, str);
  460.         if delimiterPosition > 0 then begin
  461.             head := TPCopy(str, 1, delimiterPosition - 1);
  462.             tail := TPCopy(str, delimiterPosition + length(delimiter), 255);
  463.         end; (* if *)
  464.         Split := delimiterPosition > 0;
  465.     end; (* Split *)
  466.     
  467.     procedure DrawStyledString (dlg: DialogPtr; item: integer; styledString: Str255);
  468.         (* This function draws the dialog item based on the styledString.  styledString
  469.             is a colon delimited set of fields that determines how the string is to be
  470.             drawn.  The general format is:
  471.             
  472.                 font:size:style:justification:text
  473.             
  474.             Any of these fields can be left blank but the colons must remain.
  475.             
  476.             If font is blank, Geneva is used.
  477.             If size is blank, 9 point is used.
  478.             style is a string with 0 or more characters. The characters 0..6
  479.                 turn on the corresponding StyleItem in the style. An 'h' character
  480.                 makes the text hot, ie the routine searches out text enclosed
  481.                 in angle brackets and draws it in blue underline mode.
  482.             If justification is blank, teJustLeft is used.
  483.             The text field is simply drawn to the screen.
  484.             
  485.             The implementation of this routine is typical "Peter code", ie
  486.             a million line procedure.  I just don't have the guts to
  487.             break it up into more readable chunks.  Sorry.
  488.         *)
  489.         const
  490.             defaultSize = 9;
  491.         var
  492.             defaultFont : integer;
  493.  
  494.             itemRect: Rect;
  495.             oldFont : integer;
  496.             oldSize: integer;
  497.             oldFace: Style;
  498.  
  499.             fixSize: Boolean;
  500.             textIsHot : Boolean;
  501.  
  502.             goingFine : Boolean;
  503.             this: Str255;
  504.             
  505.             fontNumber : integer;
  506.             fontSize : integer;
  507.             fontStyle: Style;
  508.             justification: integer;
  509.  
  510.             stringIndex : integer;
  511.             indexOfEndOfURL : integer;
  512.  
  513.             fi: FontInfo;
  514.             textEditH : TEHandle;
  515.             textStyleRecord : TextStyle;
  516.     begin
  517.         SetPort(dlg);
  518.         
  519.         GetFNum("Geneva", defaultFont);
  520.         
  521.         GetDItemRect(dlg, item, itemRect);
  522.  
  523.         (* Save the current window state. *)
  524.         oldFont := dlg^.txFont;
  525.         oldSize := dlg^.txSize;
  526.         oldFace := dlg^.txFace;
  527.  
  528.         textIsHot := false;
  529.         fixSize := false;
  530.         
  531.         goingFine := Split(':', styledString, this, styledString);
  532.         (* Interpret the font part of styledString. An empty string means
  533.             use the default font, otherwise use the string as the font name.
  534.         *)
  535.         if goingFine then begin
  536.             if this = '' then begin
  537.                 fontNumber := defaultFont;
  538.             end else begin
  539.                 GetFNum(this, fontNumber);
  540.                 if fontNumber = 0 then begin
  541.                     fixSize := true;
  542.                     fontNumber := defaultFont;
  543.                 end; (* if *)
  544.             end; (* if *)
  545.             goingFine := Split(':', styledString, this, styledString);
  546.         end; (* if *)
  547.         
  548.         (* Interpret the size part of styledString. An empty string denotes
  549.             the default size, otherwise evaluate the string and use that size.
  550.         *)
  551.         if goingFine then begin
  552.             if this = '' then begin
  553.                 fontSize := defaultSize;
  554.             end else begin
  555.                 fontSize := DecVal(this);
  556.             end; (* if *)
  557.             goingFine := Split(':', styledString, this, styledString);
  558.         end; (* if *)
  559.  
  560.         (* Interpret the style part of styledString. Loop through the string
  561.             setting styles based on the digits in the style string.
  562.         *)
  563.         if goingFine then begin
  564.             fontStyle := [];
  565.             for stringIndex := 1 to length(this) do begin
  566.                 case this[stringIndex] of
  567.                     '0'..'7':
  568.                         fontStyle := fontStyle + [StyleItem(ord(this[stringIndex]) - ord('0'))];
  569.                     'H', 'h':
  570.                         textIsHot := true;
  571.                     otherwise
  572.                         (* do nothing *);
  573.                 end; (* case *)
  574.             end; (* for *)
  575.             goingFine := Split(':', styledString, this, styledString);
  576.         end; (* if *)
  577.  
  578.         (* Interpret the justification part of styledString. An empty string
  579.             means the default justification (ie teJustLeft) and any other string
  580.             is interpreted as a numeric value suitable for passing to TESetAlignment.
  581.         *)
  582.         if goingFine then begin
  583.             if this = '' then begin
  584.                 justification := teJustLeft;
  585.             end else begin
  586.                 justification := DecVal(this);
  587.             end; (* if *)
  588.             TextFont(fontNumber);
  589.             TextSize(fontSize);
  590.             TextFace(fontStyle);
  591.             
  592.             (* Now fix the text size.  I actually have *no idea* what this is for. *)
  593.             if fixSize then begin
  594.                 GetFontInfo(fi);
  595.                 while (fi.ascent + fi.descent > itemRect.bottom - itemRect.top) do begin
  596.                     if fontSize > 48 then begin
  597.                         fontSize := 48;
  598.                     end else if fontSize > 36 then begin
  599.                         fontSize := 36;
  600.                     end else if fontSize > 27 then begin
  601.                         fontSize := 27;
  602.                     end else if fontSize > 24 then begin
  603.                         fontSize := 24;
  604.                     end else if fontSize > 18 then begin
  605.                         fontSize := 18;
  606.                     end else if fontSize > 14 then begin
  607.                         fontSize := 14;
  608.                     end else if fontSize > 12 then begin
  609.                         fontSize := 12;
  610.                     end else begin
  611.                         fontSize := 9;
  612.                         TextSize(fontSize);
  613.                         leave;
  614.                     end; (* if *)
  615.                     TextSize(fontSize);
  616.                     GetFontInfo(fi);
  617.                 end; (* while *)
  618.             end; (* if *)
  619.             
  620.             (* Now actually go and draw the text. First create a TEStyleHandle. *)
  621.             textEditH := TEStyleNew(itemRect,itemRect);
  622.             if textEditH <> nil then begin
  623.  
  624.                 (* Now install the text and setup the justification. *)
  625.                 TESetText(@styledString[1],length(styledString),textEditH);
  626.                 TESetAlignment(justification, textEditH);
  627.                 
  628.                 (* If the text is hot, search out text enclosed in < > and make it
  629.                     blue underlined.
  630.                 *)
  631.                 if textIsHot then begin
  632.                     for stringIndex := 1 to length(styledString) do begin
  633.                         if styledString[stringIndex] = '<' then begin
  634.                             indexOfEndOfURL := stringIndex + 1;
  635.                             while (indexOfEndOfURL <= length(styledString)) & (styledString[indexOfEndOfURL] <> '>') do begin
  636.                                 indexOfEndOfURL := indexOfEndOfURL + 1;
  637.                             end; (* while *)
  638.                             TESetSelect(stringIndex, indexOfEndOfURL - 1, textEditH);
  639.                             textStyleRecord.tsFace := fontStyle + [underline];
  640.                             textStyleRecord.tsColor.red := 0;
  641.                             textStyleRecord.tsColor.green := 0;
  642.                             textStyleRecord.tsColor.blue := $FFFF;
  643.                             TESetStyle(doFace + doColor, textStyleRecord, false, textEditH);
  644.                         end; (* if *)
  645.                     end; (* for *)
  646.                 end; (* if *)
  647.                 
  648.                 (* Finally, draw the text and dispose the TEStyleHandle. *)
  649.                 TEUpdate(itemRect, textEditH);
  650.                 TEDispose(textEditH);
  651.             end; (* if *)
  652.         end; (* if *)
  653.         
  654.         (* Clean up. *)
  655.         TextFont(oldFont);
  656.         TextSize(oldSize);
  657.         TextFace(oldFace);
  658.     end; (* DrawStyledString *)
  659.  
  660.     procedure ShiftTab (dlg: DialogPtr);
  661.         (* Performs a shift tab operation in the dialog, ie moves the text selection
  662.             to the edit text item immediately before the current one.
  663.             
  664.             This code doesn't deal well with there being no currently selected
  665.             text.  Fortunately that case never comes up, because IC always
  666.             selects the first text item before bringing up a dialog.  Something to
  667.             work on later I guess.
  668.         *)
  669.  
  670.         function IsVisibleEditText(dlg : DialogPtr; item : integer) : Boolean;
  671.             var
  672.                 kind: integer;
  673.         begin
  674.             GetDItemKind(dlg, item, kind);
  675.             IsVisibleEditText := ((kind = editText) & DialogItemHidden(dlg, item));
  676.         end; (* IsVisibleEditText *)
  677.         
  678.         var
  679.             originalItem : integer;
  680.             itemIndex : integer;
  681.             itemCount: integer;
  682.     begin
  683.         originalItem := GetSelectedDialogTextItem(dlg);
  684.         itemCount := CountDItems(dlg);
  685.         
  686.         (* We only have to do work if there's more than one item in the dialog.
  687.             Also bail out of there's no text selected because we don't deal with that case
  688.         *)
  689.         if (originalItem > 0) and (itemCount > 1) then begin
  690.  
  691.             (* Start at the originalItem and walk backwards looking for
  692.                 an unhidden text item.  If itemIndex hits 0, wrap around
  693.                 to the last item. Stop if we get back to the original
  694.                 item or we find an item.
  695.             *)
  696.             itemIndex := originalItem;
  697.             repeat
  698.                 itemIndex := itemIndex - 1;
  699.                 if itemIndex = 0 then begin
  700.                     itemIndex := itemCount;
  701.                 end; (* if *)
  702.             until (itemIndex = originalItem) | IsVisibleEditText(dlg, itemIndex);
  703.             if (itemIndex <> originalItem) & IsVisibleEditText(dlg, itemIndex) then begin
  704.                 SelectDialogItemText(dlg, itemIndex, 0, 32767);
  705.             end; (* if *)
  706.         end; (* if *)
  707.     end; (* ShiftTab *)
  708.  
  709.     procedure FlashDItem (dlg: DialogPtr; item: integer);
  710.         (* Flashes a dialog item by highlighting its control, waiting for 2 ticks
  711.             and then unhighlighting it.
  712.         *)
  713.         var junk : UInt32;
  714.     begin
  715.         HiliteControl(GetDControlHandle(dlg, item), kControlButtonPart);
  716.         Delay(2,junk);
  717.         HiliteControl(GetDControlHandle(dlg, item), 0);
  718.     end; (* FlashDItem*)
  719.  
  720.     function TrackDItem(window : WindowPtr; item : integer) : Boolean;
  721.         (* Tracks the mouse within the dialog item, returning true
  722.             if the mouse is released inside the item.
  723.         *)
  724.         var
  725.             itemRect : Rect;
  726.             inside : Boolean;
  727.             newInside : Boolean;
  728.             mousePosition : Point;
  729.     begin
  730.         SetPort(window);
  731.         GetDItemRect(window, item, itemRect);
  732.         InvertRect(itemRect);
  733.         inside := true;
  734.         while StillDown do begin
  735.             GetMouse(mousePosition);
  736.             newInside := PtInRect(mousePosition, itemRect);
  737.             if newInside <> inside then begin
  738.                 InvertRect(itemRect);
  739.                 inside := newInside;
  740.             end; (* if *)
  741.         end; (* while *)
  742.         if inside then begin
  743.             InvertRect(itemRect);
  744.         end; (* if *)
  745.         TrackDItem := inside;
  746.     end; (* TrackDItem *)
  747.  
  748.     (* ***** Initialisation ***** *)
  749.     
  750.     procedure InitICDialogs;
  751.     begin
  752.         gDefaultButtonUPP := NewUserItemProc(@DefaultButtonUserItem);
  753.         ICAssert(gDefaultButtonUPP <> nil);
  754.         
  755.         gOKModalFilterUPP := NewModalFilterProc(@OKModalFilter);
  756.         ICAssert(gOKModalFilterUPP <> nil);
  757.         
  758.         gOKCancelModalFilter := NewModalFilterProc(@OKCancelModalFilter);
  759.         ICAssert(gOKCancelModalFilter <> nil);
  760.         
  761.         gOKCancelDiscardModalFilter := NewModalFilterProc(@OKCancelDiscardModalFilter);
  762.         ICAssert(gOKCancelDiscardModalFilter <> nil);
  763.     end; (* InitICDialogs *)
  764.     
  765. end. (* ICDialogs *)
  766.